<?php
/**
 * Общий контроллер для API-методов
 */
class ApiController extends Controller
{
	// Имя модели. Переопределяется для каждого отдельного контроллера
	protected function getModelName(){}
	// Служебная переменная. Хранит экземпляр модели
	private static $_model = null;
	// Служебный метод. Возвращает экземпляр модели. Если не существует - создает.
	private function getModel()
	{
		if(self::$_model == null)
		{
			$modelName = $this->getModelName();
			self::$_model = $modelName::model();
		}
		return self::$_model;
	}
	
	public function init()
	{
		if(Yii::app()->user->isGuest)
		{
			$token = Yii::app()->request->getParam('token', null);
			$user = User::model()->findByAttributes(array('token'=>$token));
			if($user !== null)
			{
				$identity = new UserIdentity($user->email, $user->password);
				if($identity->authenticate())
				{
					Yii::app()->user->login($identity);
				}
			}

			if($identity->authenticate())
			{
				Yii::app()->user->login($identity);
			}
		}
		
		parent::init();
	}
	
	/**
	 * @return array action filters
	 */
	public function filters()
	{
		return array(
			//'accessControl', // позволяет опредить права доступа к страницам
		);
	}

	/**
	 * Определение прав доступа к страницам
	 * Этот метод используется фильтром 'accessControl'
	 * @return массив правил доступа
	 */
	public function accessRules()
	{
		return array(
			// Позволяет всем авторизованным пользователям 
			// обратиться к методам index, view, project
			array('allow',  
				'actions'=>array('index','view','project'),
				'users'=>array('@'),
			),
			// Позволяет всем пользователям, которые принадлежат ролям admin, manager и developer
			// обратиться к методам create и update
			array('allow',
				'actions'=>array('create','update'),
				'roles'=>array('admin', 'manager', 'developer'),
			),
			// Позволяет всем пользователям, которые принадлежат ролям admin и manager
			// обратиться к методу admin, delete
			array('allow',
				'actions'=>array('admin','delete'),
				'roles'=>array('admin', 'manager'),
			),
			// Запретить все остальное всем остальным пользователям
			array('deny',
				'users'=>array('*'),
			),
		);
	}
	
	/**
	 * Возвращает все объекты
	 */
	public function actionIndex()
	{
		$this->response(
			$this->modelsToJSON(self::getModel()->findAll())
		);
	}
	
	/**
	 * Возвращает все объекты, принадлежащие проекту
	 * @param type $id - id проекта
	 */
	public function actionProject($id)
	{
		$this->response(
			$this->modelsToJSON(self::getModel()->project($id)->findAll())
		);
	}
	
	/**
	 * Создание нового объекта
	 */
	public function actionCreate()
	{
		// Создаем новый экземпляр класса 
		$modelName = $this->getModelName();
		$model=new $modelName;

		// Если в пост-запросе есть данные, относящиеся к модели
		if(isset($_POST[$modelName]))
		{
			// Заполняем модель данными из POST-запроса
			$model->attributes=$_POST[$modelName];
			// Если сохранение (запись в БД) прошло успешно
			if($model->save())
			{
				// Отправляем сохраненную модель
				// и информацию об успешном выполнении (status=success)
				$this->response(CJSON::encode(
					array(
						'model' => $model->getAttributes(),
						'status' => 'success'
					)
				));
			}
			else{
				// Иначе отправляем информацию о неудачном выполнении операции
				$this->response(CJSON::encode(
					array(
						'error' => 'Произошла ошибка при сохранении объекта',
						'errorItems' => $model->getErrors(),
						'status' => 'failed'
					)
				));
			}
		}
	}
	
	/**
	 * Обновление отдельной модели
	 * @param integer $id ID модели, которая будет обновлена
	 */
	public function actionUpdate($id)
	{
		// Загружаем нужную модель по ID
		$modelName = $this->getModelName();
		$model=$this->loadModel($id);
		// Если в пост-запросе есть данные, относящиеся к модели
		if(isset($_POST[$modelName]))
		{
			// Заполняем модель данными из POST-запроса
			$model->attributes=$_POST[$modelName];
			// Если сохранение (запись в БД) прошло успешно
			if($model->save())
			{
				// Отправляем сохраненную модель
				// и информацию об успешном выполнении (status=success)
				$this->response(CJSON::encode(
					array(
						'model' => $model->getAttributes(),
						'status' => 'success'
					)
				));
			}
			else{
				// Иначе отправляем информацию о неудачном выполнении операции
				$this->response(CJSON::encode(
					array(
						'error' => 'Произошла ошибка при сохранении объекта',
						'errorItems' => $model->getErrors(),
						'status' => 'failed'
					)
				));
			}
		}
	}
	
	/**
	 * Удаление отдельной модели
	 * Если удаление прошло успешно, происходит редирект на страницу списка моделей
	 * @param integer $id ID модели для удаления
	 */
	public function actionDelete($id)
	{
		// Загружаем модель по ID и сразу запускаем удаление
		$this->loadModel($id)->delete();
		// Отправляем информацию об успешном выполнении (status=success)
		$this->response(CJSON::encode(
			array(
				'status' => 'success'
			)
		));
	}
	
	/**
	 * Возвращает модель по первичному ключу из GET параметра
	 * Если модель не найдена - генерируется исключение CHttpException с кодом 404
	 * @param integer $id ID модели для загрузки
	 * @return Issue загружаемая модель
	 * @throws CHttpException
	 */
	public function loadModel($id)
	{
		$model=self::getModel()->findByPk($id);
		if($model===null)
			throw new CHttpException(404,'Запрашиваемая страница не существует');
		return $model;
	}
	
	/**
	 * Переводит массива AR-моделей в JSON
	 * @param array of CActiveRecord $models
	 * @return string
	 */
	protected function modelsToJSON($models)
	{
		array_walk($models, function($model){
			$model = $model->getAttributes();
		});
		return CJSON::encode($models);
	}
	
	
	protected function response($json)
	{
		if(isset($_GET['callback'])){
			printf('%s(%s)', $_GET['callback'], $json);
		}
		else{
			echo $json;
		}
		Yii::app()->end();
	}
}
